package com.tsfyun.common.base.help;

import com.tsfyun.common.base.constant.BaseContextConstant;
import com.tsfyun.common.base.security.SecurityUtil;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TypeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.slf4j.MDC;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description:
 * @since Created in 2019/12/13 14:20
 */
@Slf4j
public class DingTalkNoticeUtil {

    public static void send2DingDing(HttpServletRequest request, Exception e, List<String> dingdingUrl) {
        try {
            //如果是本地windows环境则不发送
            String osName = System.getProperties().getProperty("os.name");
            if (StringUtils.isNotEmpty(osName) && osName.trim().toLowerCase().contains("windows")) {
                log.debug("本地windows环境，不推送钉钉消息");
                return;
            }
            String params = null;
            String title = request.getRequestURI();
            String ip = com.tsfyun.common.base.util.RequestUtils.getIp();
            String personIdName = null;
            String browserName = null;
            try {
                personIdName = SecurityUtil.getCurrentPersonIdAndName();
                params = RequestUtils.getRequestJsonString(request);
                browserName = RequestUtils.obtainDevice(request);
            } catch (Exception e2) {

            }
            final String loginPersonIdName = StringUtils.null2EmptyWithTrim(personIdName);
            final String requestParams = StringUtils.null2EmptyWithTrim(params);
            final String requestBrowserName = StringUtils.null2EmptyWithTrim(browserName);
            final String requestUrl = StringUtils.null2EmptyWithTrim(request.getRequestURL());
            String traceId = TypeUtils.castToString(request.getHeader(BaseContextConstant.HTTP_HEADER_TRACE_ID), MDC.get(BaseContextConstant.LOG_TRACE_ID));
            new Thread(() -> {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String crashTime = df.format(new Date());
                String text = "####xxxx请求失败业务预警####\n" +
                        "> 请求地址： " + requestUrl + "\n\n" +
                        "> 跟踪ID： " + traceId + "\n\n" +
                        "> 请求IP： " + ip + "\n\n" +
                        "> 设备： " + requestBrowserName + "\n\n" +
                        "> 用户： \n" + loginPersonIdName + "\n\n" +
                        "> 请求参数： \n" + requestParams + "\n\n" +
                        "> 堆栈信息： \n" + (Objects.nonNull(e) ? e.getMessage() : "") + "\n\n" +
                        "> ###### 出错时间： " + crashTime + " \n";
                new ExceptionDingTalkMessage(new DingTalkMessageBuilder().markdownMessage(title, text).at(null),dingdingUrl).send();
            }).start();
        } catch (Exception oe) {
            log.error("发送至钉钉异常", oe);
        }
    }

    /**
     * 针对没有request上下文请求的异常，如消息，定时器等
     * @param title
     * @param content
     * @param e
     * @param dingdingUrl
     */
    public static void send2DingDingOtherException(String title,String content,Throwable e,List<String> dingdingUrl) {
        try {
            //如果是本地windows环境则不发送
            String osName = System.getProperties().getProperty("os.name");
            if (StringUtils.isNotEmpty(osName) && osName.trim().toLowerCase().contains("windows")) {
                log.debug("本地windows环境，不推送钉钉消息");
                return;
            }
            new Thread(() -> {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String crashTime = df.format(new Date());
                String text = "####xxxx请求失败业务预警####\n" +
                        "> 出错描述： " + content + "\n\n" +
                        "> 堆栈信息： \n" + (Objects.nonNull(e) ? e.getMessage() : "") + "\n\n" +
                        "> ###### 出错时间： " + crashTime + " \n";
                new ExceptionDingTalkMessage(new DingTalkMessageBuilder().markdownMessage(title, text).at(null),dingdingUrl).send();
            }).start();
        } catch (Exception oe) {
            log.error("发送至钉钉异常", oe);
        }
    }


    public static void send2DingDingBiz(String title,String content,List<Map<String,String>> dingdingInfos,String profile) {
        try {
            //如果是本地windows环境则不发送，测试暂打开
            /*
            String osName = System.getProperties().getProperty("os.name");
            if (StringUtils.isNotEmpty(osName) && osName.trim().toLowerCase().contains("windows")) {
                log.debug("本地windows环境，不推送钉钉消息");
                return;
            }
             */
            if(Objects.equals(profile,"dev") || Objects.equals(profile,"test")) {
                return;
            }
            title = StringUtils.isEmpty(title) ? "业务通知" : title;
            Map<String,String> dingdingInfo = dingdingInfos.get(new Random().nextInt(dingdingInfos.size()));
            Long timestamp = System.currentTimeMillis();
            String secret = dingdingInfo.get("sign");
            String sign = sign(timestamp,secret);
            String requestUrl = dingdingInfo.get("url").concat("&timestamp=").concat(timestamp.toString()).concat("&sign=").concat(sign);
            String finalTitle = title;
            new Thread(()->{
                new DingBizTalkMessage(new DingTalkMessageBuilder().markdownMessage(finalTitle, content).at(null),requestUrl).send();
            }).start();
        } catch (Exception oe) {
            log.error("发送业务通知至钉钉异常", oe);
        }
    }

    public static String sign(Long timestamp,String secret) {
        String stringToSign = timestamp + "\n" + secret;
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
            return  URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
        } catch (Exception e) {
            log.error("钉钉参数签名异常",e);
        }
        return null;
    }

}
